package com.hongfeng.web.item;

import java.util.ArrayList;
import java.util.List;

import com.hongfeng.web.item.exp.FieldExpression;
import com.hongfeng.web.item.exp.OrderExpression;
import com.hongfeng.web.item.tag.FieldOperator;
import com.hongfeng.web.item.tag.LogicOperator;
import com.hongfeng.web.item.tag.OrderOperator;
import com.hongfeng.web.item.tag.RelationOperator;
import com.hongfeng.web.model.Product;

public class QueryItem {

	private List<FieldExpression> fieldExps = null;
	private List<OrderExpression> orderExps = null;
	private Class<?> entityClass;

	public <T> QueryItem(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	public List<FieldExpression> getFieldExps() {
		return fieldExps;
	}

	public List<OrderExpression> getOrderExps() {
		return orderExps;
	}

	/**
	 * IS NULL || IS NOT NULL
	 * 
	 * @param fieldName
	 * @param operator
	 */
	public void addCondition(String fieldName, FieldOperator operator) {
		if (operator == null || operator.getDimension() != 1) {
			throw new RuntimeException("此方法只可用于一目的操作符！");
		}
		this.addCondition(fieldName, operator, null);
	}

	/**
	 * 字段比较
	 * 
	 * @param fieldName
	 * @param operator
	 * @param value
	 */
	public void addCondition(String fieldName, FieldOperator operator, Object value) {
		this.addCondition(fieldName, operator, value, true);
	}

	/**
	 * 字段比较。如果条件中已经存在该字段配置，是否删除
	 * 
	 * @param fieldName
	 * @param operator
	 * @param value
	 * @param ifExistsRemove
	 */
	public void addCondition(String fieldName, FieldOperator operator, Object value, boolean ifExistsRemove) {
		this.addCondition(fieldName, operator, LogicOperator.AND, null, value, ifExistsRemove);
	}

	/**
	 * 字段比较。如果条件中已经存在该字段配置则覆盖；是与还是或操作
	 * 
	 * @param fieldName
	 * @param fieldOperator
	 * @param logicOperator
	 * @param value
	 * @param ifExistsRemove
	 */
	public void addCondition(String fieldName, FieldOperator fieldOperator, RelationOperator relationOperator,
			Object value) {
		this.addCondition(fieldName, fieldOperator, LogicOperator.AND, relationOperator, value, true);
	}

	/**
	 * 字段比较。如果条件中已经存在该字段配置，是否删除；是与还是或操作
	 * 
	 * @param fieldName
	 * @param fieldOperator
	 * @param logicOperator
	 * @param value
	 * @param ifExistsRemove
	 */
	public void addCondition(String fieldName, FieldOperator fieldOperator, RelationOperator relationOperator,
			Object value, boolean ifExistsRemove) {
		this.addCondition(fieldName, fieldOperator, LogicOperator.AND, relationOperator, value, ifExistsRemove);
	}

	/**
	 * 字段比较。如果条件中已经存在该字段配置则覆盖；是与还是或操作
	 * 
	 * @param fieldName
	 * @param fieldOperator
	 * @param logicOperator
	 * @param value
	 * @param ifExistsRemove
	 */
	public void addCondition(String fieldName, FieldOperator fieldOperator, LogicOperator logicOperator, Object value) {
		this.addCondition(fieldName, fieldOperator, logicOperator, null, value, true);
	}

	/**
	 * 字段比较。如果条件中已经存在该字段配置，是否删除；是与还是或操作
	 * 
	 * @param fieldName
	 * @param fieldOperator
	 * @param logicOperator
	 * @param value
	 * @param ifExistsRemove
	 */
	public void addCondition(String fieldName, FieldOperator fieldOperator, LogicOperator logicOperator, Object value,
			boolean ifExistsRemove) {
		this.addCondition(fieldName, fieldOperator, logicOperator, null, value, ifExistsRemove);
	}

	/**
	 * 字段比较。如果条件中已经存在该字段配置，是否删除；是与还是或操作；添加括弧操作
	 * 
	 * @param fieldName
	 * @param fieldOperator
	 * @param logicOperator
	 * @param relationOperator
	 * @param value
	 * @param ifExistsRemove
	 */
	public void addCondition(String fieldName, FieldOperator fieldOperator, LogicOperator logicOperator,
			RelationOperator relationOperator, Object value) {
		this.addCondition(fieldName, fieldOperator, logicOperator, relationOperator, value, true);
	}

	/**
	 * 字段比较。如果条件中已经存在该字段配置，是否删除；是与还是或操作；添加括弧操作
	 * 
	 * @param fieldName
	 * @param fieldOperator
	 * @param logicOperator
	 * @param relationOperator
	 * @param value
	 * @param ifExistsRemove
	 */
	public void addCondition(String fieldName, FieldOperator fieldOperator, LogicOperator logicOperator,
			RelationOperator relationOperator, Object value, boolean ifExistsRemove) {
		FieldExpression exp = new FieldExpression(fieldName, fieldOperator, logicOperator, relationOperator, value);
		if (fieldExps == null) {
			fieldExps = new ArrayList<FieldExpression>();
		}
		if (ifExistsRemove) {
			for (FieldExpression fieldExp : fieldExps) {
				if (fieldName.toLowerCase().equals(fieldExp.getPropertyName().toLowerCase())) {
					fieldExps.remove(fieldExp);
					break;
				}
			}
		}
		fieldExps.add(exp);
	}

	/**
	 * 添加排序条件
	 * 
	 * @param fieldName
	 * @param orderTag
	 */
	public void addOrder(String fieldName, OrderOperator orderTag) {
		OrderExpression exp = new OrderExpression(fieldName, orderTag);
		if (orderExps == null) {
			orderExps = new ArrayList<OrderExpression>();
		}
		for (OrderExpression orderExp : orderExps) {
			if (fieldName.toLowerCase().equals(orderExp.getPropertyName().toLowerCase())) {
				orderExps.remove(orderExp);
				break;
			}
		}
		orderExps.add(exp);
	}

	/**
	 * 生成HQL语句
	 * 
	 * @return
	 */
	public String generateHql() {
		StringBuffer buffer = new StringBuffer();
		buffer.append("FROM ").append(this.entityClass.getName()).append(" t ");
		this.generateFieldExpression(buffer);
		this.generateOrderExpression(buffer);
		return buffer.toString();
	}

	/**
	 * 获取属性值的集合，与属性要一一对应
	 * 
	 * @return
	 */
	public List<Object> generateHqlValues() {
		List<Object> values = null;
		if (fieldExps != null) {
			values = new ArrayList<Object>();
			for (FieldExpression exp : fieldExps) {
				values.add(exp.getValue());
			}
		}
		return values;
	}

	/**
	 * 生成属性表达式
	 * 
	 * @param buffer
	 */
	private void generateFieldExpression(StringBuffer buffer) {
		if (this.fieldExps == null) {
			return;
		}
		buffer.append(" WHERE ");
		for (int i = 0; i < fieldExps.size(); i++) {
			FieldExpression exp = fieldExps.get(i);
			FieldOperator fieldOper = exp.getFieldOperator();
			LogicOperator logicOper = exp.getLogicOperator();
			RelationOperator relOper = exp.getRelationOperator();
			if (i > 0) {
				if (logicOper != null) {
					String lov = logicOper.getValue();
					buffer.append(" ").append(lov).append(" ");
				} else {
					buffer.append(" AND ");
				}
			}
			if (relOper != null && RelationOperator.LEFT.equals(relOper)) {
				buffer.append(relOper.getValue());
			}
			if (!FieldOperator.LIKE.equals(fieldOper)) {
				buffer.append(" t.").append(exp.getPropertyName());
			} else {
				buffer.append(" UPPER(t.").append(exp.getPropertyName()).append(") ");

			}
			buffer.append(" ").append(fieldOper.getOpertor());
			if (fieldOper.getDimension() > 1) {
				if (FieldOperator.LIKE.equals(fieldOper)) {
					buffer.append(" UPPER(?) ");
				} else {
					buffer.append(" ? ");
				}
			}
			if (relOper != null && RelationOperator.RIGHT.equals(relOper)) {
				buffer.append(relOper.getValue());
			}
		}
	}

	/**
	 * 生成排序表达式
	 * 
	 * @param buffer
	 */
	private void generateOrderExpression(StringBuffer buffer) {
		if (orderExps == null) {
			return;
		}
		buffer.append(" ORDER BY ");
		int index = 0;
		for (OrderExpression exp : orderExps) {
			buffer.append(" t.").append(exp.getPropertyName()).append(" ").append(exp.getOrderTag().getValue());
			index++;
			if (index < orderExps.size()) {
				buffer.append(" , ");
			}
		}
	}

	public static void main(String[] args) {
		QueryItem item = new QueryItem(Product.class);
		item.addCondition("username", FieldOperator.LIKE, RelationOperator.LEFT, "k");
		item.addCondition("username", FieldOperator.LIKE, LogicOperator.OR, RelationOperator.RIGHT, "j", false);
		item.addCondition("password", FieldOperator.EQUAL, "1212");
		item.addCondition("createTime", FieldOperator.LARGER_EQUAL, "2012-01-01", false);
		item.addCondition("createTime", FieldOperator.LESS_EQUAL, "2012-02-02", false);
		item.addOrder("username", OrderOperator.ASC);
		item.addOrder("createTime", OrderOperator.DESC);
		System.out.println(item.generateHql());
	}
}
